﻿/*This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace Table_Storage_Component
{
        [DtsPipelineComponent(DisplayName = "Azure Table Storage",
            UITypeName = "Table_Storage_Component.ComponentUI,Table Storage Component,Version=1.0.0.0,Culture=neutral,PublicKeyToken=908a54124b105ed2",
            //IconResource = "",
            ComponentType = ComponentType.Transform)]
	     
	        public class TableStorageComponent : PipelineComponent
	        {
                private List<ColumnInfo> columnInformation;
                private GenericTableContext context;
                private struct ColumnInfo
                {
                    public int BufferColumnIndex;
                    public string ColumnName;
                }

                public override void ProvideComponentProperties()
                {
                    // Reset the component.
                    base.RemoveAllInputsOutputsAndCustomProperties();
                    ComponentMetaData.RuntimeConnectionCollection.RemoveAll();

                    // Add output
                    IDTSOutput100 output = ComponentMetaData.OutputCollection.New();
                    output.Name = "Output";

                    // Properties
                    var storageConnectionStringProperty = this.ComponentMetaData.CustomPropertyCollection.New();
                    storageConnectionStringProperty.Name = "StorageConnectionString";
                    storageConnectionStringProperty.Description = "Azure storage connection string";
                    storageConnectionStringProperty.Value = "UseDevelopmentStorage=true";
                    storageConnectionStringProperty.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

                    var tableNameProperty = this.ComponentMetaData.CustomPropertyCollection.New();
                    tableNameProperty.Name = "TableName";
                    tableNameProperty.Description = "Name of the source table";
                    tableNameProperty.Value = string.Empty;
                    tableNameProperty.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

                    var filterValueProperty = this.ComponentMetaData.CustomPropertyCollection.New();
                    filterValueProperty.Name = "FiltreDate";
                    filterValueProperty.Description = "From Date: ";
                    filterValueProperty.Value = string.Empty;
                    filterValueProperty.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;
                    
                }
                public string GetComponentProperty(string propertyName)
                {
                    return (string)this.ComponentMetaData.CustomPropertyCollection[propertyName].Value;
                }
                public override IDTSCustomProperty100 SetComponentProperty(string propertyName, object propertyValue)
                {

                    var resultingColumn = base.SetComponentProperty(propertyName, propertyValue);

                    var storageConnectionString = (string)this.ComponentMetaData.CustomPropertyCollection["StorageConnectionString"].Value;
                    var tableName = (string)this.ComponentMetaData.CustomPropertyCollection["TableName"].Value;


                    if (!string.IsNullOrEmpty(storageConnectionString) && !string.IsNullOrEmpty(tableName) && (propertyName=="StorageConnectionString" ||propertyName == "TableName") )
                    {
                        try
                        {
                            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(storageConnectionString);

                            GenericTableContext context = new GenericTableContext(cloudStorageAccount.TableEndpoint.AbsoluteUri, cloudStorageAccount.Credentials);

                            GenericEntity firstRow = context.GetFirstOrDefault(tableName);
                            if (firstRow != null)
                            {

                                //IDTSOutput100 output = this.ComponentMetaData.OutputCollection[0];
                                this.ComponentMetaData.OutputCollection.RemoveObjectByIndex(0);
                                IDTSOutput100 output = ComponentMetaData.OutputCollection.New();
                                output.Name = "Output";
                                //A arranger
                                foreach (var column in firstRow.GetProperties())
                                {

                                    IDTSOutputColumn100 newOutputCol = output.OutputColumnCollection.New();
                                    newOutputCol.Name = column.ColumnName;
                                    newOutputCol.SetDataTypeProperties(column.DtsType, column.Length, 0, 0, 0);
                                }
                            }
                            else
                            {
                                //handle error
                            }
                        }
                        catch (Exception e)
                        {

                        }
                    }

                    return resultingColumn;
                }


                public override void PreExecute()
                {
                    
                    this.columnInformation = new List<ColumnInfo>();
                    IDTSOutput100 output = ComponentMetaData.OutputCollection[0];

                    var cloudStorageAccount = CloudStorageAccount.Parse((string)this.ComponentMetaData.CustomPropertyCollection["StorageConnectionString"].Value);
                    context = new GenericTableContext(cloudStorageAccount.TableEndpoint.AbsoluteUri, cloudStorageAccount.Credentials);

                    foreach (IDTSOutputColumn100 col in output.OutputColumnCollection)
                    {
                        ColumnInfo ci = new ColumnInfo();
                        ci.BufferColumnIndex = BufferManager.FindColumnByLineageID(output.Buffer, col.LineageID);
                        ci.ColumnName = col.Name;
                        columnInformation.Add(ci);
                    }
                }
                
                public override DTSValidationStatus Validate()
                {
                    bool pbCancel = false;

                    // Validate that there is one input.
                    if (ComponentMetaData.OutputCollection.Count < 1)
                    {
                        ComponentMetaData.FireError(0, ComponentMetaData.Name, "The Table should have at least 1 Colum", "", 0, out pbCancel);
                        return DTSValidationStatus.VS_ISCORRUPT;
                    }

                    // Validate that the UserName custom property is set.
                    if (ComponentMetaData.CustomPropertyCollection["TableName"].Value == null || ((string)ComponentMetaData.CustomPropertyCollection["TableName"].Value).Length == 0)
                    {
                        
                        ComponentMetaData.FireError(0, ComponentMetaData.Name, "The TableName property must be set.", "", 0, out pbCancel);
                        return DTSValidationStatus.VS_ISBROKEN;
                    }
                    if (ComponentMetaData.CustomPropertyCollection["StorageConnectionString"].Value == null || ((string)ComponentMetaData.CustomPropertyCollection["StorageConnectionString"].Value).Length == 0)
                    {
                        ComponentMetaData.FireError(0, ComponentMetaData.Name, "The StorageConnectionString property must be set.", "", 0, out pbCancel);
                        return DTSValidationStatus.VS_ISBROKEN;
                    }
                    DateTime ValidDate;
                    if (!String.IsNullOrEmpty(ComponentMetaData.CustomPropertyCollection["FiltreDate"].Value) && !DateTime.TryParse(ComponentMetaData.CustomPropertyCollection["FiltreDate"].Value,out ValidDate))
                    {
                        ComponentMetaData.FireError(0, ComponentMetaData.Name, "The FiltreDate property should be null or DD/MM/YYYY HH:MM:SS [" + ComponentMetaData.CustomPropertyCollection["FiltreDate"].Value+"]", "", 0, out pbCancel);
                        return DTSValidationStatus.VS_ISBROKEN;
                    }


                    // Let the base class verify that the input column reflects the output 
                    // of the upstream component.
                    return base.Validate();
                }

                public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)
                {
                    IDTSOutput100 output = ComponentMetaData.OutputCollection[0];
                    PipelineBuffer buffer = buffers[0];
                    CloudTableQuery<GenericEntity> Query = null;
                    try
                    {
                        DateTime FiltreDate = Convert.ToDateTime((string)this.ComponentMetaData.CustomPropertyCollection["FiltreDate"].Value);
                        Query = this.context.CreateQuery<GenericEntity>((string)this.ComponentMetaData.CustomPropertyCollection["TableName"].Value).Where(x => x.Timestamp >= FiltreDate).AsTableServiceQuery();
                    }
                    catch (Exception e)
                    {
                        Query = this.context.CreateQuery<GenericEntity>((string)this.ComponentMetaData.CustomPropertyCollection["TableName"].Value).AsTableServiceQuery();
                    }
                    
                    foreach (var item in Query)
                    {
                        buffer.AddRow();

                        for (int x = 0; x < columnInformation.Count; x++)
                        {
                            var ci = (ColumnInfo)columnInformation[x];
                            var value = item[ci.ColumnName].Value;
                            if (value != null)
                            {
                                buffer[ci.BufferColumnIndex] = value;
                            }
                            else
                            {
                                buffer.SetNull(ci.BufferColumnIndex);
                            }
                        }
                    }

                    buffer.SetEndOfRowset();
                }
	        }
}
